package cn.hinglo.common.ratelimit.interceptor;

import cn.hinglo.common.ratelimit.RateLimitManager;
import cn.hinglo.common.ratelimit.annotation.EnableConcurrencyLimit;
import cn.hinglo.common.ratelimit.annotation.EnablePreIpLimit;
import cn.hinglo.common.ratelimit.annotation.EnableRequestLimit;
import cn.hinglo.common.ratelimit.annotation.EnableUserLimit;
import cn.hinglo.common.ratelimit.config.LimitationInfo;
import cn.hutool.extra.servlet.ServletUtil;
import lombok.Setter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;


/**
 * @author HingLo
 * @createTime: 2018/9/21 16:32
 * @description: 限流拦截器实现
 */
@Setter
public abstract class AbstractLimitationInterceptor {

    /**
     * 限流manager单例对象
     */
    private final RateLimitManager rateLimitManager = RateLimitManager.me();

    /**
     * 请求头限流的请求头名称,默认使用User-Agent作为request限流策略
     */
    private String header = null;

    /**
     * 认证用户请求头限流的请求头
     */
    private String user = null;

    protected boolean run(Method method, HttpServletResponse response, HttpServletRequest request) throws IOException, ServletException {
        boolean bool = true;
        String url = request.getRequestURI();
        // 方法并发限流
        EnableConcurrencyLimit enableConcurrencyLimit = method.getAnnotation(EnableConcurrencyLimit.class);
        if (enableConcurrencyLimit != null) {
            bool = rateLimitManager.rateLimit(url, new LimitationInfo(enableConcurrencyLimit), response, request);
        }
        initTarget(header, user);
        // 指定的请求头限流
        EnableRequestLimit enableRequestLimit = method.getAnnotation(EnableRequestLimit.class);
        if (bool && enableRequestLimit != null) {
            if (header != null) {
                bool = rateLimitManager.rateLimit(url + request.getHeader(header), new LimitationInfo(enableRequestLimit), response,
                        request);
            }
        }
        // 方法对IP的限流
        EnablePreIpLimit enablePreIpLimit = method.getAnnotation(EnablePreIpLimit.class);
        if (bool && enablePreIpLimit != null) {
            bool = rateLimitManager.rateLimit(url + ServletUtil.getClientIP(request), new LimitationInfo(enablePreIpLimit), response,
                    request);
        }
        // 对同一用户的限流
        EnableUserLimit enableUserLimit = method.getAnnotation(EnableUserLimit.class);
        if (bool && enableUserLimit != null) {
            if (user != null) {
                bool = rateLimitManager.rateLimit(url + user, new LimitationInfo(enableUserLimit), response, request);
            }
        }
        return bool;
    }

    /**
     * 限流拦截器继承此类,然后根据需求初始化 header与 user 用于 request与 用户限流
     *
     * @param header 请求头
     * @param user   用户唯一标示符
     */
    protected abstract void initTarget(String header, String user);

}
